package com.spd.singlechipupgrade.utils;

import static java.lang.Thread.sleep;

import android.annotation.SuppressLint;

import com.spd.singlechipupgrade.App;
import com.speedata.libutils.DataConversionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

public class Upgrade {

    @SuppressLint("SdCardPath")
    public static void runWriteBin() throws InterruptedException {
        //gpio55 高   ：BOOT拉高
        //gpio56 低   ：复位拉低
        //延时
        //gpio56 高   ：复位拉低

        //打开串口 ttysWK1  默认8位数据  1位停止 无校验

        if (intSync()) {    //发0x7f  直到返回0x79(ACK) 或 0x1f(NACK)
            System.out.println("同步波特率成功");
            setStrMsg("同步波特率成功");
            if (getCom()) {  //发0x00 0xff  直到返回0x79(ACK)
                System.out.println("单片机bootloader版本，支持指令代码获取成功");
                setStrMsg("单片机bootloader版本，支持指令代码获取成功");
                if (getID()) { //发0x02 0xfd  直到返回0x79(ACK)
                    System.out.println("单片机ID获取成功");
                    setStrMsg("单片机ID获取成功");
                    if (eraseMemory()) {
                        System.out.println("flash全擦成功");
                        setStrMsg("flash全擦成功，准备写固件数据");
                        writeBin("/sdcard/gd32isp.bin");
                        sleep(500);
                        System.out.println("writeBin结束");
                        setStrMsg("writeBin结束，升级完成");
                        //verifyBin("/sdcard/1.bin");
                    } else {
                        System.out.println("flash 全擦失败");
                    }
                } else {
                    System.out.println("单片机ID获取失败");
                    setStrMsg("单片机ID获取失败,升级失败");
                }


            } else {
                System.out.println("单片机bootloader版本，支持指令代码获取失败");
                setStrMsg("单片机bootloader版本,支持指令代码获取失败,升级失败");
            }
        } else {
            System.out.println("同步波特率失败");
            setStrMsg("单片机反馈同步波特率失败。请重新点击一次升级按钮");
        }
        System.out.println("runWriteBin结束");
        //gpio55 低   ：BOOT拉低
        //gpio56 低   ：复位拉低
        //延时
        //gpio56 高   ：复位拉低
    }

    public static boolean eraseMemory() {
        Send("44bb");
        //Send("bb");
        try {
            sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        Ack1();

        Send("ffff00");
        //Send("ff");
        //Send("00");
        try {
            sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return Ack1();
    }

    public static boolean getID() {
        Send("02fd");
        //Send("fd");
        try {
            sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return Ack1();
    }

    public static boolean Ack1() {

        System.out.println("ack:" + str);
        return getStr().indexOf("79") == 0;
    }

    public static void Send(String cmd) {

        if (cmd.length() < 2) {
            cmd = "0" + cmd;
        }

        // 串口发cmd
        if (App.getInstance().getSerialPortHelper() != null) {
            App.getInstance().getSerialPortHelper().sendBytes(
                    DataConversionUtils.HexString2Bytes(cmd));
        }

        try {
            sleep(25);//20
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void Senddata(byte[] cmd) {


        // 串口发cmd
        if (App.getInstance().getSerialPortHelper() != null) {
            App.getInstance().getSerialPortHelper().sendBytes(cmd);
        }

        try {
            sleep(50);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


    }

    private static String str = "";

    private static String strMsg = "";

    public static String getStrMsg() {
        if ("".equals(strMsg)) {
            return "";
        }

        return strMsg;
    }

    public static void setStrMsg(String result) {
        strMsg = result;
    }

    public static String getStr() {
        if ("".equals(str)) {
            return "";
        }
        System.out.println(str);
        //Log.d("aaa",str);
        return str.substring(0, 2);
    }

    public static void setStr(String result) {
        str = result;
    }

    public static boolean intSync() {
        Send("7F");

        try {
            sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return Ack1();
    }

    public static boolean getCom() {
        Send("00ff");
        //Send("ff");

        try {
            sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return Ack1();
    }

    public static void writeMemoryBlock(byte[] data, int addr, int len) {
        byte[] temp = new byte[4];
        temp[0] = (byte) ((addr >> 24) & 0xff);
        temp[1] = (byte) ((addr >> 16) & 0xff);
        temp[2] = (byte) ((addr >> 8) & 0xff);
        temp[3] = (byte) (addr & 0xff);
        Send("31ce");
        //Send("ce");

        while (!Ack1()) {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        String hexString = "0" + Integer.toHexString(addr);
        byte IDXOR = checkSum(temp, 4);
        if (Integer.toHexString(IDXOR & 0xFF).length() == 1) {
            hexString += ("0" + Integer.toHexString(IDXOR & 0xFF));
        } else {
            hexString += Integer.toHexString(IDXOR & 0xFF);
        }

        Send(hexString);


        try {
            sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        while (!Ack1()) {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }


        //数据写入
        int len1 = len - 1;
        String dataString = Integer.toHexString(len1);
        //Send(Integer.toHexString(len1));
        for (int i = 0; i < len; i++) {
            if (data[i] >= 0) {
                if (data[i] < 16) {
                    dataString += ("0" + Integer.toHexString(data[i] & 0xff));
                } else {
                    dataString += (Integer.toHexString(data[i] & 0xff));
                }
            } else {
                data[i] = (byte) (256 + data[i]);
                dataString += (Integer.toHexString(data[i] & 0xff));
            }
        }
        byte dataXOR = checkSum(data, len);

        byte tmp = (byte) (len1 ^ dataXOR);

        if (Integer.toHexString(tmp & 0xff).length() == 1) {
            dataString += ("0" + Integer.toHexString(tmp & 0xff));
        } else {
            dataString += (Integer.toHexString(tmp & 0xff));
        }

        System.out.println("tem=" + tmp);
        Send(dataString);

        while (!Ack1()) {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }

    public static void writeBin(String binFile) {
        //把binFile 文件读成byte[]
        File file = new File(binFile);
        byte[] binData = new byte[(int) file.length()];

        try (FileInputStream fis = new FileInputStream(file)) {
            fis.read(binData);
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (int i = 0; i <= ((binData.length + 1) / 128); i++) {
            int offset = i * 128;
            byte[] sendData = Arrays.copyOfRange(binData, offset, 128 + offset);

            writeMemoryBlock(sendData, 0x08000000 + offset, sendData.length);
            System.out.println("写入第" + i + "块成功");
            setStrMsg("写入第" + i + "块成功");
        }
    }

    public static byte checkSum(byte[] data, int len) {
        byte cs = 0x00;

        for (int i = 0; i < len; i++) {
            cs ^= data[i];
        }

        return cs;
        //return Integer.toHexString(cs);
    }

}
